package com.simple.car.loader.server.business;

import android.os.Environment;

import com.simple.car.loader.server.annotation.Controller;
import com.simple.car.loader.server.annotation.Mapping;
import com.simple.car.loader.server.annotation.RequestParam;
import com.simple.car.loader.server.entity.RemoteFile;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Controller("/file/controller")
public class FileController {

    private Pattern pattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}).(mp4|mp4.cpy)");

    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");

    @Mapping("/root")
    public Map<String, String> getRoot() {
        Map<String, String> map = new HashMap<>();
        map.put("root", Environment.getExternalStorageDirectory().getAbsolutePath());
        return map;
    }

    @Mapping("/lookup")
    public Map<String, List<RemoteFile>> fileLookup(@RequestParam(value = "path", necessary = false) String path) {
        File file = Environment.getExternalStorageDirectory();
        Map<String, List<RemoteFile>> map = new HashMap<>();
        if (path == null) {
            File[] list = file.listFiles();
            if (list == null) {
                list = new File[0];
            }
            List<RemoteFile> collect = Arrays.stream(list).map(file1 -> {
                RemoteFile remoteFile = new RemoteFile();
                remoteFile.setPath(file1.getName());
                remoteFile.setIsFile(file1.isFile() ? "file" : "dir");
                return remoteFile;
            }).collect(Collectors.toList());
            map.put("files", collect);
            return map;
        }
        file = new File(path);
        File[] list = file.listFiles();
        if (list == null) {
            list = new File[0];
        }
        List<RemoteFile> collect = Arrays.stream(list).map(file1 -> {
            RemoteFile remoteFile = new RemoteFile();
            remoteFile.setPath(file1.getName());
            remoteFile.setIsFile(file1.isFile() ? "file" : "dir");
            return remoteFile;
        }).sorted((o1, o2) -> {
            String path1 = o1.getPath();
            String path2 = o2.getPath();
            Matcher matcher1 = pattern.matcher(path1);
            Matcher matcher2 = pattern.matcher(path2);
            if (!matcher1.matches()){
                return 0;
            }
            if (!matcher2.matches()){
                return 0;
            }
            return LocalDateTime.parse(matcher1.group(1), dateTimeFormatter).compareTo(LocalDateTime.parse(matcher2.group(1), dateTimeFormatter)) * -1;
        }).collect(Collectors.toList());
        map.put("files", collect);
        return map;
    }

    @Mapping("/download")
    public void download(Socket socket, @RequestParam("path") String path) {
        File file = new File(path);
        try (
                BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)
        ) {
            dataOutputStream.writeLong(file.length());
            dataOutputStream.flush();
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(byteArrayOutputStream.toByteArray());
            byte[] data = new byte[8 * 1024];
            int i;
            while ((i = bufferedInputStream.read(data)) != -1) {
                outputStream.write(data, 0, i);
            }
            socket.getOutputStream().flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
